package com.cr.front.news.service.es;

import com.alibaba.fastjson.JSON;
import com.cr.front.news.dao.repository.NewsRepository;
import com.cr.front.news.pojo.entity.News;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.List;


// 定义一个Spring Boot的启动监听器，用于在Spring应用上下文初始化完成后执行特定任务
@Component
@Slf4j
public class StartupApplicationListener implements ApplicationListener<ContextRefreshedEvent> {

    // 注入Elasticsearch初始化服务实例
    @Autowired
    private ElasticSearchInitializer initializer;

    // 构造函数，用于依赖注入
    // 通常不需要此构造函数，因为@Autowired会自动注入依赖，但这里提供了显式注入的示例
    public StartupApplicationListener(ElasticSearchInitializer initializer) {
        this.initializer = initializer;
    }

    // 注入News的仓库层实例，用于数据库操作
    @Autowired
    private NewsRepository newsRepository;

    // 当应用程序上下文刷新完成时调用此方法
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        try {
            // 调用初始化服务的createIndexIfNotExists方法，确保Elasticsearch的索引存在
            log.info("ES: 初始化创建索引 . . . ");
            initializer.createIndexIfNotExists();

            // 从数据库中获取缓存新闻列表，注意：在生产环境中，如果数据量大，应使用分页查询
            List<News> newsList = newsRepository.getCacheNews();
            log.info("预热缓存的数据 : {} 条", newsList.size()); // 使用size()代替toArray().length，更高效

            // 调用insertES方法，批量插入新闻数据到Elasticsearch
            insertES(newsList);

        } catch (IOException e) {
            // 捕获并抛出异常，确保任何I/O异常都能被上层捕获处理
            throw new RuntimeException(e);
        }
    }

    // 注入RestHighLevelClient实例，用于与Elasticsearch交互
    @Autowired
    private RestHighLevelClient client;

    // 插入或更新新闻数据到Elasticsearch的私有方法
    private void insertES(List<News> newsList) {
        // 遍历新闻列表，逐条插入或更新到Elasticsearch
        for (News news : newsList) {
            // 创建IndexRequest对象，指定索引名称
            IndexRequest indexRequest = new IndexRequest("news");

            // 设置文档ID
            indexRequest.id(news.getId().toString());

            // 序列化News对象为JSON格式的字符串
            String sourceNews = JSON.toJSONString(news);

            // 设置IndexRequest的文档内容，使用JSON格式
            indexRequest.source(sourceNews, XContentType.JSON);

            // 执行插入或更新操作
            try {
                client.index(indexRequest, RequestOptions.DEFAULT);
            } catch (IOException e) {
                // 记录插入或更新失败的日志，并抛出异常
                log.error("插入ES失败", e);
            }
        }
        log.info("预热缓存数据结束...");
    }
}